﻿#region << 版 本 注 释 >>

/*----------------------------------------------------------------
* 类 名 称 ：ResMgr
* 类 描 述 ：
* 作    者 ：henrychang
* 创建时间 ：2019/1/6 18:42:00
*******************************************************************
* Copyright @ henrychang 2019. All rights reserved.
*******************************************************************
//----------------------------------------------------------------*/

#endregion << 版 本 注 释 >>

using System.Collections.Generic;
using TouchFish.SingletonClass;
using UnityEngine;

namespace TouchFish.AssetLoad
{
    public class ResMgr : SingletonMono<ResMgr>, IEnumeratorTaskMgr, ISingleton
    {
        /// <summary>
        /// 初始化bin文件
        /// </summary>
        public static void Init()
        {
            Instance.InitResMgr();
        }

        public void OnSingletonInit()
        {
        }

        public int Count
        {
            get { return mResList.Count; }
        }

        private readonly Dictionary<string, IRes> mResDictionary = new Dictionary<string, IRes>();
        private readonly List<IRes> mResList = new List<IRes>();
        [SerializeField] private int mCurrentCoroutineCount;

        private int mMaxCoroutineCount = 8; //最快协成大概在6到8之间

        private LinkedList<IEnumeratorTask> mIEnumeratorTaskStack = new LinkedList<IEnumeratorTask>();

        //Res 在ResMgr中 删除的问题，ResMgr定时收集列表中的Res然后删除
        private bool mIsResMapDirty;

        public void InitResMgr()
        {
            //#if UNITY_EDITOR
            //            if (AbstractRes.SimulateAssetBundleInEditor)
            //            {
            //                EditorRuntimeAssetDataCollector.BuildDataTable();
            //            }
            //            else
            //#endif
            //            {
            //                ResDatas.Instance.Reset();
            //                var outResult = new List<string>();
            //                FileMgr.Instance.GetFileInInner("asset_bindle_config.bin", outResult);
            //                foreach (var outRes in outResult)
            //                {
            //                    ResDatas.Instance.LoadFromFile(outRes);
            //                }
            //            }

            //            ResDatas.Instance.SwitchLanguage("cn");
        }

        public void ClearOnUpdate()
        {
            mIsResMapDirty = true;
        }

        public void PushIEnumeratorTask(IEnumeratorTask task)
        {
            if (task == null)
            {
                return;
            }

            mIEnumeratorTaskStack.AddLast(task);
            TryStartNextIEnumeratorTask();
        }

        public IRes GetRes(string ownerBundleName, string assetName, bool createNew = false)
        {
            IRes res = null;

            if (mResDictionary.TryGetValue((ownerBundleName + assetName).ToLower(), out res))
            {
                return res;
            }

            if (!createNew)
            {
                return null;
            }

            res = ResFactory.Create(assetName, ownerBundleName);

            if (res != null)
            {
                mResDictionary.Add((ownerBundleName + assetName).ToLower(), res);

                if (!mResList.Contains(res))
                {
                    mResList.Add(res);
                }
            }
            return res;
        }

        public IRes GetRes(string assetName, bool createNew = false)
        {
            IRes res = null;
            if (mResDictionary.TryGetValue(assetName, out res))
            {
                return res;
            }

            if (!createNew)
            {
                Debug.Log(string.Format("createNew:{0}", createNew));
                return null;
            }

            res = ResFactory.Create(assetName);

            if (res != null)
            {
                mResDictionary.Add(assetName, res);
                if (!mResList.Contains(res))
                {
                    mResList.Add(res);
                }
            }
            return res;
        }

        public R GetAsset<R>(string name) where R : Object
        {
            IRes res = null;
            if (mResDictionary.TryGetValue(name, out res))
            {
                return res.Asset as R;
            }

            return null;
        }

        private void Update()
        {
            if (mIsResMapDirty)
            {
                RemoveUnusedRes();
            }
        }

        public void RemoveUnusedRes()
        {
            if (!mIsResMapDirty)
            {
                return;
            }

            mIsResMapDirty = false;

            for (var i = mResList.Count - 1; i >= 0; --i)
            {
                var res = mResList[i];
                if (res.RefCount <= 0 && res.State != ResState.Loading)
                {
                    if (res.ReleaseRes())
                    {
                        mResList.RemoveAt(i);
                        mResDictionary.Remove(res.AssetName);
                        mResDictionary.Remove((res.OwnerBundleName + res.AssetName).ToLower());
                        res.Recycle2Cache();
                    }
                }
            }
        }

        private void OnGUI()
        {
            //if (Platform.IsEditor && Input.GetKey(KeyCode.F1))
            //{
            //    GUILayout.BeginVertical("box");

            //    mResList.ForEach(res =>
            //    {
            //        GUILayout.Label("bundleName:{0} assetName:{1} refCount:{2}".FillFormat(res.OwnerBundleName,
            //            res.AssetName,
            //            res.RefCount));
            //    });

            //    GUILayout.EndVertical();
            //}
        }

        private void OnIEnumeratorTaskFinish()
        {
            --mCurrentCoroutineCount;
            TryStartNextIEnumeratorTask();
        }

        private void TryStartNextIEnumeratorTask()
        {
            if (mIEnumeratorTaskStack.Count == 0)
            {
                return;
            }

            if (mCurrentCoroutineCount >= mMaxCoroutineCount)
            {
                return;
            }

            var task = mIEnumeratorTaskStack.First.Value;
            mIEnumeratorTaskStack.RemoveFirst();

            ++mCurrentCoroutineCount;
            StartCoroutine(task.DoLoadAsync(OnIEnumeratorTaskFinish));
        }
    }
}